%include "boot.inc"
section  .text
bits     16
extern   setup_start
global   _start

_start:
	mov ax, cs
	mov ds, ax
	mov es, ax
	mov ss, ax
	mov fs, ax
	mov sp, 0x7c00

	mov bp, _msg_hello
	mov ax, 0x1301
	mov bx, 0x0007
	mov cx, _msg_hello_len
	mov dx, 0
	int 0x10

_load:
	mov  ax, REST_SECTOR_START; 起始 lba 号
	mov  bx, REST_ADDR; 写入的内存地址
	mov  cx, REST_SECTORS_COUNT; 读取的扇区数
	call rd_disk_m16

_ok_load:
	mov bp, _msg_load_ok
	mov ax, 0x1301
	mov bx, 0x000c
	mov cx, _msg_load_ok_len
	mov dx, 0x0100
	int 0x10

	jmp setup_start

	;----------
	; rd_disk_m16: 16位实模式, 磁盘读取函数
	; 参数:
	; ax: 起始 lba 号(lba 从 0 开始编号)
	; bx: 写入的内存地址
	; cx: 读取扇区数
	; ----------

rd_disk_m16:
	push ax; 保存 ax
	;    1. 设置要读取的扇区数
	mov  dx, 0x1f2
	mov  al, cl
	out  dx, al
	;    2. 设置 lba 号
	pop  ax; 还原 ax, 保存的 lba 号
	push cx; 保存 cx
	mov  dx, 0x1f3
	out  dx, al; lba 0-7
	mov  dx, 0x1f4
	mov  cl, 8
	shr  ax, cl
	out  dx, al; lba 8-15
	mov  dx, 0x1f5
	mov  al, 0
	out  dx, al; lba 16-23, 直接设置 0
	mov  dx, 0x1f6
	mov  al, 0xe0; 0b1110_0000, 主盘, lba 模式, lba 24-27 位 0
	out  dx, al
	;    3. 向 0x1f7 端口写入读命令
	mov  dx, 0x1f7
	mov  al, 0x20
	out  dx, al
	;    4. 检测硬盘状态

_not_ready:
	nop ; 防止循环消耗时间
	in  al, dx; 还是 0x1f7 读时是状态寄存器
	and al, 0x88; 0b1000_1000, 取位 7(BSY) 和 3(DRQ).
	cmp al, 0x08; 3 位为 1 说明数据准备好了
	jnz _not_ready; 3 位 不为 1, 重新检测

	;   5. 从 0x1f0 端口读出数据
	pop ax; push cx 保存的扇区数给 ax
	mov dx, 256
	mul dx; ax = ax * 256, 因为一次 2 字节, 所以 次数 = 扇区数 * 512 / 2
	mov cx, ax
	mov dx, 0x1f0

_read_loop:
	in   ax, dx
	mov  [bx], ax
	add  bx, 2
	loop _read_loop

	ret

_msg_hello:
	db "Hello, world!", 0

_msg_hello_end:
	_msg_hello_len equ _msg_hello_end - _msg_hello

_msg_load_ok:
	db "Load setup ok!", 0

_msg_load_ok_end:
	_msg_load_ok_len equ _msg_load_ok_end - _msg_load_ok

	times 510 - ($-$$) db 0
	db    0x55, 0xaa
